const { arrayIncludesSubarray } = require('../utils')

module.exports = (options, app) => {
  return async function authorization(ctx, next) {
    const { header } = ctx.request
    const token = header.authorization?.slice(7) || '' // Bearer的长度 + 1空格 = 7

    const userInfo = await app.jwt.verify(token, app.config.jwt.secret)
    if (userInfo) {
      ctx.userInfo = userInfo
    }

    /**
     * 角色权限校验
     * @param {String} mode
     * @property {String} mode.open - 开放型接口，无需做权限校验
     * @property {String} mode.needlogin - 需要登录（检验token是否有效）
     * @property {String} mode.self - 必须账号本人操作
     * @property {String} mode.permission - 用户拥有指定权限
     * @property {String} mode.role - 用户拥有指定角色
     * @property {String} mode.admin - 必须为超级管理员
     * @param {String|Array} flag 对比校验值，当mode为self时flag为字符串，当mode为role或permission时flag为数组
     * @returns {Boolean} 校验结果
     */
    ctx.checkAuthority = (mode, flag) => {
      // 超级管理员拥有所有权限
      if (userInfo.role.includes('admin')) {
        return true
      }
      // 校验结果
      let result = false
      switch (mode) {
        case 'open':
          result = true
          break
        case 'needlogin':
          result = !!userInfo
          if (!result) ctx.throw(401, '请先登录!')
          break
        case 'self':
          result = userInfo.username === flag
          if (!result) ctx.throw(403, '非本人操作!')
          break
        case 'role':
          result = arrayIncludesSubarray(userInfo.role, flag)
          if (!result) ctx.throw(403, '权限不足，禁止访问')
          break
        case 'permission':
          result = arrayIncludesSubarray(userInfo.permission, flag)
          if (!result) ctx.throw(403, '权限不足，禁止访问')
          break
        case 'admin':
          result = userInfo.role.includes('admin')
          if (!result) ctx.throw(403, '权限不足，禁止访问')
          break
        default:
          result = false
          break
      }
      return result
    }

    await next()
  }
}
